#include "Vector.h"

Vector::Vector()
{
	this->initialize(0.0, 0.0, 0.0);
}

Vector::Vector(const Vector &v)
{
	this->initialize(v.getX(), v.getY(), v.getZ());
}

Vector::Vector(const Real &x)
{
	this->initialize(x, 0.0, 0.0);
}

Vector::Vector(const double &x)
{
	this->initialize(x, 0.0, 0.0);
}

Vector::Vector(const Real &x, const Real &y)
{
	this->initialize(x, y, 0.0);
}

Vector::Vector(const double &x, const double &y)
{
	this->initialize(x, y, 0.0);
}

Vector::Vector(const Real &x, const Real &y, const Real &z)
{
	this->initialize(x, y, z);
}

Vector::Vector(const double &x, const double &y, const double &z)
{
	this->initialize(x, y, z);
}

void Vector::initialize(const Real &x, const Real &y, const Real &z)
{
	this->coordinates[Vector::X_INDEX] = x;
	this->coordinates[Vector::Y_INDEX] = y;
	this->coordinates[Vector::Z_INDEX] = z;
}

inline Real Vector::getX() const {
	return this->coordinates[Vector::X_INDEX];
}

inline Real Vector::getY() const {
	return this->coordinates[Vector::Y_INDEX];
}

inline Real Vector::getZ() const {
	return this->coordinates[Vector::Z_INDEX];
}

Vector Vector::operator+(const Vector &v) const
{
	return Vector(this->getX() + v.getX(), this->getY() + v.getY(), this->getZ() + v.getZ());
}

Vector Vector::operator-(const Vector &v) const
{
	return Vector(this->getX() - v.getX(), this->getY() - v.getY(), this->getZ() - v.getZ());
}

Vector Vector::operator*(const Real &aReal) const
{
	return Vector(this->getX() * aReal, this->getY() * aReal, this->getZ() * aReal);
}

Vector operator*(const Real &aReal, const Vector &v)
{
	return v * aReal;
}

bool Vector::operator==(const Vector &v) const
{
	return this->coordinates[Vector::X_INDEX] == v.coordinates[Vector::X_INDEX] &&
		this->coordinates[Vector::Y_INDEX] == v.coordinates[Vector::Y_INDEX] &&
		this->coordinates[Vector::Z_INDEX] == v.coordinates[Vector::Z_INDEX];
}

std::ostream &operator<<(std::ostream &out, const Vector &v)
{
	out << "("  << v.coordinates[Vector::X_INDEX]
		<< ", " << v.coordinates[Vector::Y_INDEX]
		<< ", " << v.coordinates[Vector::Z_INDEX] << ")";

	return out; 
}

Real Vector::norm2() const
{
	return (this->coordinates[Vector::X_INDEX] * this->coordinates[Vector::X_INDEX] +
		this->coordinates[Vector::Y_INDEX] * this->coordinates[Vector::Y_INDEX] +
		this->coordinates[Vector::Z_INDEX] * this->coordinates[Vector::Z_INDEX]).sqrt();
}

Vector Vector::dotProduct(const Vector &v) const
{
	Real product;

	for (unsigned int index = 0; index < Vector::COORDINATES_COUNT; ++index) {
		product = product + (this->coordinates[index] + v.coordinates[index]);
	}

	return product;
}

const unsigned int Vector::X_INDEX(0);
const unsigned int Vector::Y_INDEX(1);
const unsigned int Vector::Z_INDEX(2);

const unsigned int COORDINATES_COUNT(3);
